import hashlib
import os
import re
import secrets
from typing import Dict, List

from flask import current_app


def app_path() -> str:
    """
    项目根目录
    """
    return current_app.config.get("APP_ABS_PATH")


def src_path() -> str:
    """
    项目src目录
    """
    return os.path.join(app_path(), "src")


def static_path() -> str:
    """
    项目static目录
    """
    return os.path.join(app_path(), "static")


def logging_path() -> str:
    """
    项目logs目录
    """
    return os.path.join(app_path(), "logs")


def md5(ss: str = ''):
    """
    md5 加密
    """
    return hashlib.md5(ss.encode('utf-8')).hexdigest()


def calculate_file_md5(file_path: str = ""):
    """
    计算文件md5值
    """
    with open(file_path, 'rb') as f:
        md5_obj = hashlib.md5()
        while True:
            data = f.read(4096)
            if not data:
                break
            md5_obj.update(data)
    return md5_obj.hexdigest()


def get_int_list_from_string(_str: str = '', _d: str = ','):
    """
    由字符串得到整形数组
    """
    # 先转换为 string 格式数据
    _str = str(_str).strip()
    if _str == '':
        return []
    # 先转换为 string 格式数据
    _d = str(_d).strip()
    if _d == '':
        _d = ','
    return [int(x) for x in _str.split(_d) if x.isdigit()]


def get_positive_int_list(ls: List = None):
    """
    得到正整数list
    """
    result = []
    if ls is None:
        ls = []
    if len(ls) < 1:
        return result
    for one in ls:
        one = int(str(one))
        if one > 0:
            result.append(one)
    return result


def list_to_tree(dts: List[Dict[str, any]], pk: str = 'id', pid: str = 'pid', child: str = '_sub', root: int = 0):
    """
    把数据结构：
    [
        {'id': 2, 'pid': 0, 'name': '水果'},
        {'id': 5, 'pid': 0, 'name': '主食'},
        {'id': 3, 'pid': 2, 'name': '西瓜'},
        {'id': 4, 'pid': 2, 'name': '菠萝'},
        {'id': 6, 'pid': 5, 'name': '大米'},
        {'id': 7, 'pid': 5, 'name': '面粉'},
        {'id': 8, 'pid': 6, 'name': '东北大米'},
        {'id': 9, 'pid': 6, 'name': '泰国大米'},
    ]
    转化为树状：
    [
        {
            'id': 2,
            'pid': 0,
            'name': '水果',
            '_sub': [
                {'id': 3, 'pid': 2, 'name': '西瓜'},
                {'id': 4, 'pid': 2, 'name': '菠萝'},
            ]
        },
        {
            'id': 5,
            'pid': 0,
            'name': '主食',
            '_sub': [
                {
                    'id': 7,
                    'pid': 5,
                    'name': '面粉'
                },
                {
                    'id': 6,
                    'pid': 5,
                    'name': '大米',
                    '_sub': [
                        {'id': 8, 'pid': 6, 'name': '东北大米'},
                        {'id': 9, 'pid': 6, 'name': '泰国大米'},
                    ]
                },
            ]
        }
    ]
    """
    tree = []
    refer = {}
    key = 0
    for data in dts:
        refer[data[pk]] = dts[key]
        key += 1
    key = 0
    for data in dts:
        parent_id = data[pid]
        if root == parent_id:
            tree.append(dts[key])
        else:
            if parent_id in refer.keys():
                if child not in refer[parent_id].keys():
                    refer[parent_id][child] = []
                refer[parent_id][child].append(dts[key])
        key += 1
    return tree


def float_dict(dts: Dict = None, sub: str = '_sub', rs_list: Dict = None):
    """
    配合 list_to_tree 把树转换成一维
        dts
        sub
        rs_list
    """
    if rs_list is None:
        rs_list = []
    if len(dts) < 1:
        return
    for dt in dts:
        if sub in dt:
            sub_dts = dt[sub]
            del dt[sub]
            rs_list.append(dt)
            float_dict(sub_dts, sub, rs_list)
        else:
            rs_list.append(dt)


def random_str(ll: int = 20):
    """
    随机码
    :param ll:
    :return:
    """
    base_str = 'abcdefghijklmnopqrstuvwxyz123456789'
    ss = ''
    for i in range(ll):
        ss += secrets.choice(base_str)
    return ss


def get_datetime_string(ts: int = 0, fmt: str = '%Y-%m-%d %H:%M:%S'):
    """
    格式化时间戳
    """
    from time import strftime, localtime, time
    ts = int(ts)
    if ts < 1:
        ts = localtime(time())
    else:
        ts = localtime(ts)
    return strftime(fmt, ts)


def validate_phone_number(phone_number):
    """
    是否手机号码
    """
    pattern = r"^1[3456789]\d{9}$"
    if re.match(pattern, phone_number):
        return True
    else:
        return False


def request_ip(request) -> str:
    """
    请求IP
    """
    ip = request.remote_addr
    if 'X-Forwarded-For' in request.headers:
        ip = request.headers.getlist("X-Forwarded-For")[0]
    return ip
